package main

import (
	"bufio"
	"fmt"
	"os"

	flag "github.com/spf13/pflag"
)

type selpg_args struct {
	start_page  int
	end_page    int
	in_filename string
	page_len    int
	page_type   bool // false is \f  true is page end
	print_dest  string
}

var (
	sp *int
	ep *int
	lp *int
	fp *bool
	dp *string
)

const INT_MAX = int(^uint(0) >> 1)

func Init() {
	sp = flag.IntP("number1", "s", -1, "set start page")
	ep = flag.IntP("number2", "e", -1, "set end page")
	lp = flag.IntP("number3", "l", 72, "set length of page")
	dp = flag.StringP("&d", "d", "non", "set destination")
	fp = flag.BoolP("f", "f", false, "use char to judge page")
}

func process_args(sa *selpg_args) (bool, error) {
	s := *sp
	e := *ep
	l := *lp
	d := *dp
	f := *fp

	if e == -1 || s == -1 {
		fmt.Println("Not enough arguments")
		return false, nil
	}

	if s < 1 || s > INT_MAX-1 {
		fmt.Println("invalid start oage!")
		return false, nil
	}

	if e < 1 || e > INT_MAX-1 {
		fmt.Println("invalid end stage")
		return false, nil
	}

	if s > e {
		fmt.Println("The start page should larger than the end page")
		return false, nil
	}

	sa.start_page = s
	sa.end_page = e

	// set page lines number
	if l != 72 {
		if l < 1 || l > INT_MAX-1 {
			fmt.Println("limit page number invalid!")
			return false, nil
		}
		sa.page_len = l
	}

	if f != false {
		sa.page_type = true
	}

	if d != "non" {
		sa.print_dest = d
	}

	if flag.NArg() != 1 {
		fmt.Println("invalid non-flag args number")
		return false, nil
	}

	input_filename := flag.Arg(0)
	_, err := os.Open(input_filename)
	if err != nil {

		fmt.Println("can't open file :", input_filename)
		return false, err
	}
	sa.in_filename = input_filename
	return true, nil
}

func process_input(sa *selpg_args) error {
	read_file, err := os.Open(sa.in_filename)

	if err != nil { //如果打开文件出错，则需要给用户一些提示
		fmt.Println("An error occurred on opening the inputfile")
		return err // exit the function on error
	}

	defer read_file.Close()

	if sa.print_dest == "non" { //控制台写入
		inputReader := bufio.NewReader(read_file)

		if sa.page_type == false { //使用\f作为分页符
			counter := 1
			for {
				inputString, err := inputReader.ReadString('\f') //我们将inputReader里面的字符串按行进行读取。
				if err != nil {
					break
				}
				if counter >= sa.start_page && counter <= sa.end_page {
					fmt.Print(inputString) //往文件写入相应的字符串。
				}
				counter += 1
			}
		} else { //使用行数as.pagelen作为分页
			pageCounter := 1
			end := false
			for {
				lineCounter := 0
				for {
					inputString, err := inputReader.ReadString('\n') //我们将inputReader里面的字符串按行进行读取。
					if err != nil {
						end = true
						break
					}
					if inputString[0] == '\f' {
						break
					}
					if pageCounter >= sa.start_page && pageCounter <= sa.end_page {
						fmt.Print(inputString) //往控制台写出字符串
					}
					lineCounter += 1
				}
				for lineCounter <= sa.page_len && pageCounter >= sa.start_page && pageCounter <= sa.end_page {
					fmt.Println("")
					lineCounter += 1
				}
				pageCounter += 1
				if end == true {
					break
				}
			}
		}
	} else { //文件写入
		write_file, err := os.Create(sa.print_dest)
		if err != nil {
			fmt.Println("An error occurred on opening the outputfile")
			return err
		}
		defer write_file.Close()
		inputReader := bufio.NewReader(read_file)

		if sa.page_type == false { //使用\f作为分页符
			counter := 1
			for {
				inputString, err := inputReader.ReadString('\f') //我们将inputReader里面的字符串按行进行读取。
				if err != nil {
					break
				}
				if counter >= sa.start_page && counter <= sa.end_page {
					write_file.WriteString(inputString) //往文件写入相应的字符串。
				}
				counter += 1
			}
		} else { //使用行数as.pagelen作为分页
			pageCounter := 1
			end := false
			for {
				lineCounter := 0
				for {
					inputString, err := inputReader.ReadString('\n') //我们将inputReader里面的字符串按行进行读取。
					if err != nil {
						end = true
						break
					}
					if inputString[0] == '\f' {
						break
					}
					if pageCounter >= sa.start_page && pageCounter <= sa.end_page {
						write_file.WriteString(inputString) //往文件写入相应的字符串。
					}
					lineCounter += 1
				}
				for lineCounter < sa.page_len && pageCounter >= sa.start_page && pageCounter <= sa.end_page {
					write_file.WriteString("\n")
					lineCounter += 1
				}
				pageCounter += 1
				if end == true {
					break
				}
			}
		}
	}
	return nil
}

func main() {
	Init()
	flag.Parse()

	sa := selpg_args{-1, -1, "non", 72, false, "non"}
	is_completed, err := process_args(&sa)
	if is_completed == true && err == nil {
		process_input(&sa)
	} else {
		return
	}
}
